package com.purdue.edu.psychotron.client;
import java.util.ArrayList;
import java.util.Date;
import java.util.Stack;

import com.google.common.collect.Lists;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
import com.google.gwt.user.client.Cookies;

import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RichTextArea;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TabBar;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.purdue.edu.psychotron.client.entity.User;
import com.purdue.edu.psychotron.client.service.UserService;
import com.purdue.edu.psychotron.client.service.UserServiceAsync;
import com.purdue.edu.psychotron.shared.Pair;
import com.purdue.edu.psychotron.shared.Quad;
import com.purdue.edu.psychotron.shared.SeparateChainingHashST;
import com.purdue.edu.psychotron.shared.SideBar;

public class CloudMessenger extends Composite
{
	/*-----------Basic Information-------------*/
	String userFullName;
	String userId;
	String userLogin;
	String Status;
	String selectedContactLogin;
	String selectedContactId;
	String selectedPendingId;
	String selectedBlockedId;
	private final UserServiceAsync userService = GWT.create(UserService.class);
	/*------------LayOut--------------*/
	DockPanel room = new DockPanel();
	TextCell textCell = new TextCell();
	TextArea inputBox = new TextArea();
	CellList<String> contactsCellList = new CellList<String>(textCell); 			// <Full Name>
	CellList<String> blockedContactsCellList = new CellList<String>(textCell);		// <Full Name>
	CellList<String> pendingContactsCellList = new CellList<String>(textCell);		// <Full Name>
	TextArea chattingHistoryDisplay = new TextArea();
	VerticalPanel centralVPanel = new VerticalPanel();
	VerticalPanel westVPanel = new VerticalPanel();
	Button addNewContactButton = new Button("Add New Contact");
	Button deleteContactButton = new Button("Delete Contact");
	Button acceptContactButton = new Button("Accept Contact");
	Button rejectContactButton = new Button("Reject Contact");
	SideBar toolBar = new SideBar();
	Button sendMessageButton = new Button("Send");
	Button requestMessageButton = new Button("Request Message");
	Button exitCloudMessengerButton = new Button("Exit Cloud Messenger");
	Label yourContactsLabel = new Label();
	Label yourBlockedContactsLabel = new Label();
	Label yourPendingContactsLabel = new Label();
	Button viewChattingHistoryButton = new Button("View Chatting History");
	/*-------------------------------Shared among Divs-----------------------------------*/
	DialogBox generalDialogBox = new DialogBox();
	Button closeButton = new Button("Close");
	Button refreshContactsButton = new Button("Refresh Contacts");
	Label textToServerLabel = new Label();
	HTML serverResponseLabel = new HTML();
	VerticalPanel dialogVPanel = new VerticalPanel();
	/*-----------------------------------------------------------------------*/

	SingleSelectionModel<String> contactSelectionModel;
	SingleSelectionModel<String> pendingSelectionModel;
	SingleSelectionModel<String> blockedSelectionModel;

	/*------------Contact Management----------------*/
	ArrayList<Quad<String, String, String, String>> contactInfoBundleList = new ArrayList<Quad<String, String, String, String>>();	
	ArrayList<Quad<String, String, String, String>> blockedContactInfoBundleList = new ArrayList<Quad<String, String, String, String>> ();	
	ArrayList<Quad<String, String, String, String>> pendingContactInfoBundleList = new ArrayList<Quad<String, String, String, String>> ();	
	/*-------------Message Management---------------*/
	Stack<String> chatHistory = new Stack<String>();
	SeparateChainingHashST<String, String> chattingHistoryStoreLocal = new SeparateChainingHashST<String, String>();

	public CloudMessenger(String userId)
	{

		super();
		this.userId = userId;
		userInfoInitialization();
		layOutInitialization();
		updateChattingEnvironment();

		updateAndRefreshContacts();
		startMessageQueryProcess(1);
		startContactUpdateProcess(10);
		initWidget(room);
	}

	/*--------------------- User Info Initialization -----------------------------*/
	public void userInfoInitialization(){
		userService.getUserFullNameByUserId(userId, new AsyncCallback<String>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("getUserFullNameByUserId Failure");

			}
			@Override
			public void onSuccess(String result) {
				userFullName = result;
			}

		});

		userService.getUserLoginByUserId(userId, new AsyncCallback<String>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("getUserLoginByUserId Failure");

			}
			@Override
			public void onSuccess(String result) {
				userLogin = result;
			}

		});
	}


	/*--------------------- Layout Configuration & Handlers-----------------------------*/
	public void layOutInitialization()
	{
		room.setBorderWidth(5);
		room.setPixelSize(1000, 600);
		room.setTitle("My Messenger Panel");
		room.setSpacing(10);

		generalDialogBox.setStyleName("generalDialogBox_CloudMessenger");

		generalDialogBox.setText("generalDialogBox");
		generalDialogBox.setAnimationEnabled(true);
		closeButton.getElement().setId("closeButton");	
		dialogVPanel.addStyleName("dialogVPanel");

		dialogVPanel.add(new HTML("<b>Sending ID to the server:</b>"));
		dialogVPanel.add(textToServerLabel);
		dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));
		dialogVPanel.add(serverResponseLabel);
		dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_LEFT);
		dialogVPanel.add(closeButton);

		generalDialogBox.setWidget(dialogVPanel);

		// Add a handler to close the DialogBox
		closeButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				dialogVPanel.clear();
				generalDialogBox.hide();
				generalDialogBox.clear();
				room.remove(generalDialogBox);
				updateAndRefreshContacts();
			}
		});

		yourContactsLabel.setText("-- Your Contacts --");

		contactsCellList.setTitle("Your Contacts");
		contactsCellList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
		contactsCellList.setSelectionModel(createContactSelectionModel());

		yourBlockedContactsLabel.setText("-- Blocked Contacts --");

		blockedContactsCellList.setTitle("Blocked Contacts");
		blockedContactsCellList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
		blockedContactsCellList.setSelectionModel(createBlockedSelectionModel());
		
		yourPendingContactsLabel.setText("-- Pending Contacts --");
		
		pendingContactsCellList.setTitle("Your Pending Contacts");
		pendingContactsCellList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
		pendingContactsCellList.setSelectionModel(createPendingSelectionModel());
		
		addNewContactButton.addClickHandler(new AddNewContactButtonHandler());
		deleteContactButton.addClickHandler(new DeleteContactButtonHandler());
		refreshContactsButton.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				updateAndRefreshContacts();
			}
		});
		
		acceptContactButton.addClickHandler(new AcceptContactButtonHandler());
		rejectContactButton.addClickHandler(new RejectContactButtonHandler());
		
		viewChattingHistoryButton.addClickHandler(new ViewChattingHistoryButtonHandler());

		toolBar.add(addNewContactButton);
		toolBar.add(deleteContactButton);
		toolBar.add(acceptContactButton);
		toolBar.add(rejectContactButton);
		toolBar.add(refreshContactsButton);
		toolBar.add(viewChattingHistoryButton);

		chattingHistoryDisplay.setEnabled(false);
		chattingHistoryDisplay.setPixelSize(600, 300);

		inputBox.setEnabled(true);
		inputBox.setFocus(true);
		inputBox.setTitle("Input Box");
		inputBox.setText("Enter Your Message Here");
		inputBox.setPixelSize(600, 100);
		inputBox.addKeyUpHandler(new InputBoxHandler());

		sendMessageButton.addClickHandler(new SendMessageButtonHandler());

		centralVPanel.add(chattingHistoryDisplay);
		centralVPanel.add(inputBox);
		centralVPanel.add(sendMessageButton);
		centralVPanel.add(requestMessageButton);
		requestMessageButton.addClickHandler(new requestMessageButtonHandler());
		exitCloudMessengerButton.addClickHandler(new ExitCloudMessengerButtonHandler());

		room.add(toolBar, DockPanel.EAST);
		westVPanel.add(contactsCellList);
		westVPanel.add(blockedContactsCellList);
		westVPanel.add(pendingContactsCellList);
		room.add(westVPanel, DockPanel.WEST);
		room.add(centralVPanel, DockPanel.CENTER);
		room.add(exitCloudMessengerButton, DockPanel.SOUTH);
		//generalDialogBox.center();

		RootPanel.get("divCloudMessenger").add(room);
	}

	class RejectContactButtonHandler implements ClickHandler{

		@Override
		public void onClick(ClickEvent event) {
			rejectContact();
		}
		
	}
	
	class AcceptContactButtonHandler implements ClickHandler{

		@Override
		public void onClick(ClickEvent event) {
			acceptContact();
		}
		
	}
	
	class ViewChattingHistoryButtonHandler implements ClickHandler{

		@Override
		public void onClick(ClickEvent event) {

			userService.getChattingHistoryByIds(userId, selectedContactId, new AsyncCallback<String>(){

				@Override
				public void onFailure(Throwable caught) {
					Window.alert("userService.getChattingHistoryByIds");
				}

				@Override
				public void onSuccess(String result) {
					generalDialogBox.clear();
					generalDialogBox.setPixelSize(610, 300);
					generalDialogBox.setText("View History with "+selectedContactId);
					generalDialogBox.setAnimationEnabled(true);

					final TextArea displayHistoryBox = new TextArea();
					displayHistoryBox.setPixelSize(600, 250);
					displayHistoryBox.setEnabled(false);
					dialogVPanel.clear();
					dialogVPanel.setPixelSize(600, 290);

					dialogVPanel.add(new HTML("<b>History</b>"));
					displayHistoryBox.setText(result);
					dialogVPanel.add(displayHistoryBox);
					dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_LEFT);

					Button clearHistoryButton = new Button("Clear history");
					clearHistoryButton.addClickHandler(new ClickHandler(){

						@Override
						public void onClick(ClickEvent event) {
							userService.clearChattingHistoryByIds(userId, selectedContactId, new AsyncCallback<Void>(){

								@Override
								public void onFailure(Throwable caught) {
									Window.alert("userService.clearChattingHistoryByIds - Failure");
								}

								@Override
								public void onSuccess(Void result) {
									displayHistoryBox.setText("");

								}

							});

						}

					});

					dialogVPanel.add(clearHistoryButton);
					dialogVPanel.add(closeButton);

					// Add a handler to close the DialogBox
					closeButton.addClickHandler(new ClickHandler() {
						public void onClick(ClickEvent event) {
							dialogVPanel.clear();
							generalDialogBox.hide();
							generalDialogBox.clear();
							room.remove(generalDialogBox);
							updateAndRefreshContacts();
						}
					});
					generalDialogBox.setWidget(dialogVPanel);
					generalDialogBox.center();

				}

			});






		}

	}

	class SendMessageButtonHandler implements ClickHandler
	{
		@Override
		public void onClick(ClickEvent event) {
			collectRecordDisplaySendMessage();
		}	
	}

	class ExitCloudMessengerButtonHandler implements ClickHandler
	{
		@Override
		public void onClick(ClickEvent event) {
			userService.disengageCloudMessengerForUserId(userId, selectedContactId, new AsyncCallback<Void>(){
				@Override
				public void onFailure(Throwable caught) {
					Window.alert("disengageCloudMessengerForUserId - Failure");
				}
				@Override
				public void onSuccess(Void result) {
					RootPanel.get("divLobby").setVisible(true);
					RootPanel.get("divCloudMessenger").setVisible(false);	

				}

			});
		}	
	}

	class InputBoxHandler implements KeyUpHandler 
	{
		@Override
		public void onKeyUp(KeyUpEvent event) {
			if (event.isAnyModifierKeyDown() && (event.getNativeKeyCode() == KeyCodes.KEY_ENTER)) {
				collectRecordDisplaySendMessage();
			}
		}
	}

	public SingleSelectionModel<String> createContactSelectionModel(){
		contactSelectionModel = new SingleSelectionModel<String>();
		contactSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
			public void onSelectionChange(SelectionChangeEvent event) {
				String selected = contactSelectionModel.getSelectedObject();
			//	Window.alert("You have selected "+selected);
				if (selected != null) {
					
					// This checks if we need to refresh the contact history diplay upon new contact is selected
					for(Quad<String, String, String, String> p: contactInfoBundleList){
						if(p.getC().equals(selected))
						{
							if(!selectedContactId.equals(p.getA()))
								chattingHistoryDisplay.setText("");
							selectedContactId = p.getA();	
						}
					}
				}
			}
		});
		return contactSelectionModel;
	}
	
	public SingleSelectionModel<String> createPendingSelectionModel(){
		pendingSelectionModel = new SingleSelectionModel<String>();
		pendingSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
			public void onSelectionChange(SelectionChangeEvent event) {
				String selected = pendingSelectionModel.getSelectedObject();
				
				for(Quad<String, String, String, String> p: pendingContactInfoBundleList){
					if(p.getC().equals(selected))
					{
						selectedPendingId = p.getA();	
					}
				}
				Window.alert("You have selected Pending - "+selected+" - ID = "+selectedPendingId);
			}
		});
		return pendingSelectionModel;
	}
	
	public SingleSelectionModel<String> createBlockedSelectionModel(){
		blockedSelectionModel = new SingleSelectionModel<String>();
		blockedSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
			public void onSelectionChange(SelectionChangeEvent event) {
				String selected = blockedSelectionModel.getSelectedObject();
				
				for(Quad<String, String, String, String> p: blockedContactInfoBundleList){
					if(p.getC().equals(selected))
					{
						selectedBlockedId = p.getA();	
					}
				}
				Window.alert("You have selected Blocked - "+selected+" - ID = "+selectedBlockedId);
			}
		});
		return blockedSelectionModel;
	}
	
	class requestMessageButtonHandler implements ClickHandler{

		@Override
		public void onClick(ClickEvent event) {
			requestMessage();
		}

	}

	class DeleteContactButtonHandler implements ClickHandler
	{
		DialogBox deleteContactDialogBox = new DialogBox();
		VerticalPanel vPanel = new VerticalPanel();			// Attention ! DialogBox must have a panel to add buttons, otherwise, will not load

		@Override
		public void onClick(ClickEvent event) {		
			Button enter = new Button("Enter");
			enter.addClickHandler(new EnterButtonHandler());

			Button cancel = new Button("Cancel");
			cancel.addClickHandler(new CancelButtonHandler());

			Button block = new Button("Add to Blocked List");

			deleteContactDialogBox.setAnimationEnabled(true);
			if(selectedContactId == null){
				cancel.setText("Abort");
				vPanel.add(cancel);
				deleteContactDialogBox.add(vPanel);
				deleteContactDialogBox.setText("An Existing Contact Must Be Selected");
			}else{
				enter.setText("Yes, I do");
				cancel.setText("Rather Not.");
				block.addClickHandler(new BlockButtonHandler());
				vPanel.add(enter);
				vPanel.add(block);
				vPanel.add(cancel);
				deleteContactDialogBox.add(vPanel);
				deleteContactDialogBox.setText("Continue?");
			}
			deleteContactDialogBox.center();
		}

		class BlockButtonHandler implements ClickHandler{
			@Override
			public void onClick(ClickEvent event) {
				vPanel.clear();
				deleteContactDialogBox.clear();
				deleteContactDialogBox.hide();
				removeContact();	
				addToBlockedList();
			}
		}

		class CancelButtonHandler implements ClickHandler{
			@Override
			public void onClick(ClickEvent event) {
				vPanel.clear();
				deleteContactDialogBox.clear();
				deleteContactDialogBox.hide();
			}
		}

		class EnterButtonHandler implements ClickHandler{

			@Override
			public void onClick(ClickEvent event) {
				vPanel.clear();
				deleteContactDialogBox.clear();
				deleteContactDialogBox.hide();
				removeContact();	
			}

		}
	}

	class AddNewContactButtonHandler implements ClickHandler
	{
		TextBox enterBox = new TextBox();
		DialogBox addNewContactDialogBox = new DialogBox();
		VerticalPanel vPanel = new VerticalPanel();

		@Override
		public void onClick(ClickEvent event) {

			addNewContactDialogBox.setAnimationEnabled(true);
			addNewContactDialogBox.setText("Please Enter Target Client's Login");

			vPanel.add(enterBox);
			Button enter = new Button("Enter");
			enter.addClickHandler(new EnterButtonHandler());
			Button cancel = new Button("Cancel");
			cancel.addClickHandler(new CancelButtonHandler());
			vPanel.add(enterBox);
			vPanel.add(enter);
			vPanel.add(cancel);
			addNewContactDialogBox.setWidget(vPanel);
			addNewContactDialogBox.center();
		}
		class CancelButtonHandler implements ClickHandler{

			@Override
			public void onClick(ClickEvent event) {
				addNewContactDialogBox.clear();
				addNewContactDialogBox.hide();
				vPanel.clear();
			}

		}
		class EnterButtonHandler implements ClickHandler
		{
			@Override
			public void onClick(ClickEvent event) {
				String addUserLogin = enterBox.getText();
				userService.addNewContactByUserId(userId, addUserLogin, new AsyncCallback<String>(){

					@Override
					public void onFailure(Throwable caught) {
						Window.alert("userService.addNewContactByUserId - Failure");
						addNewContactDialogBox.clear();
						addNewContactDialogBox.hide();
						vPanel.clear();					}

					@Override
					public void onSuccess(String result) {
						Window.alert(result);
						addNewContactDialogBox.clear();
						addNewContactDialogBox.hide();
						vPanel.clear();
						updateAndRefreshContacts();
					}
				});
			}

		}

	}

	/*--------------------- Contacts Management -----------------------------*/

	public void updateAndRefreshContacts(){
		
		userService.getContactInfoBundleListByUserId(userId, new AsyncCallback<ArrayList<Quad<String, String, String, String>>>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("userService.getContactInfoBundleListByUserId - Failure");
			}

			@Override
			public void onSuccess(
					ArrayList<Quad<String, String, String, String>> result) {
				contactInfoBundleList = result;
				ArrayList<String> roster = new ArrayList<String>();
				for(Quad<String, String, String, String> q : contactInfoBundleList){
					roster.add(q.getC());
				}
				contactsCellList.setRowData(roster);
			}});
		
		userService.getBlockedContactInfoBundleListByUserId(userId, new AsyncCallback<ArrayList<Quad<String, String, String, String>>>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("userService.getBlockedContactInfoBundleListByUserId - Failure");
			}

			@Override
			public void onSuccess(
					ArrayList<Quad<String, String, String, String>> result) {
				blockedContactInfoBundleList = result;
				ArrayList<String> roster = new ArrayList<String>();
				for(Quad<String, String, String, String> q : blockedContactInfoBundleList){
					roster.add(q.getC());
				}
				blockedContactsCellList.setRowData(roster);
			}});
		
		userService.getPendingContactInfoBundleListByUserId(userId, new AsyncCallback<ArrayList<Quad<String, String, String, String>>>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("userService.getPendingContactInfoBundleListByUserId - Failure");
			}

			@Override
			public void onSuccess(
					ArrayList<Quad<String, String, String, String>> result) {
				pendingContactInfoBundleList = result;
				ArrayList<String> roster = new ArrayList<String>();
				for(Quad<String, String, String, String> q : pendingContactInfoBundleList){
					roster.add(q.getC());
				}
				pendingContactsCellList.setRowData(roster);
			}});
		
		
		
		
		
		westVPanel.remove(yourContactsLabel);
		westVPanel.remove(contactsCellList);
		westVPanel.add(yourContactsLabel);
		westVPanel.add(contactsCellList);
		
		westVPanel.remove(yourPendingContactsLabel);
		westVPanel.remove(pendingContactsCellList);
		westVPanel.add(yourPendingContactsLabel);
		westVPanel.add(pendingContactsCellList);
		
		westVPanel.remove(yourBlockedContactsLabel);
		westVPanel.remove(blockedContactsCellList);
		westVPanel.add(yourBlockedContactsLabel);
		westVPanel.add(blockedContactsCellList);
	}

	public void removeContact(){
		userService.removeContactByUserId(userId, selectedContactId, new AsyncCallback<Void>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("removeContactByUserId - Failure");
			}

			@Override
			public void onSuccess(Void result) {
				for(Quad<String, String, String, String> p : contactInfoBundleList){
					if(p.getA().equals(selectedContactId))
						contactInfoBundleList.remove(p);
				}
				updateAndRefreshContacts();
			}
		});
	}

	// Will used the selectedContactId which is the contact currently selected
	public void addToBlockedList(){	
		userService.blockContactForRequesterIdByTargetId(userId, selectedContactId, new AsyncCallback<Void>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("userService.blockContactForRequesterIdByTargetId Failure");
			}

			@Override
			public void onSuccess(Void result) {
				Window.alert("Successful!");	
			}
		});
		updateAndRefreshContacts();
	}

	public void rejectContact(){
		userService.rejectContactByTargetLogin(userId, selectedPendingId, new AsyncCallback<Void>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("userService.rejectContactByTargetLogin - Failure");
			}

			@Override
			public void onSuccess(Void result) {
				updateAndRefreshContacts();
			}
			
		});
	}
	
	public void acceptContact(){
		userService.acceptContactByTargetLogin(userId, selectedPendingId, new AsyncCallback<Void>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("userService.acceptContactByTargetLogin - Failure");
			}

			@Override
			public void onSuccess(Void result) {
				updateAndRefreshContacts();
			}
			
		});
	}


	/*--------------------- Message Maganement -----------------------------*/
	// This function is a bundle of many sub functions
	public void collectRecordDisplaySendMessage(){
		if(selectedContactId == null){
			Window.alert("You must select a person");
			return;
		}
		//Window.alert("collectRecordDisplaySendMessage");
		String msg = inputBox.getText();
		msg = formatMessage(msg);
		inputBox.setText("");	// Reset inputBox
		addToDisplay(msg);
		sendMessage(msg);

		if(chattingHistoryStoreLocal.get(selectedContactId) != null){
			msg = chattingHistoryStoreLocal.get(selectedContactId) + "\r\n" + msg;		// Message Recording Finished
		}
		addToLocalChattingHistory(msg);

	}

	// Add time stamp and sender info as message head
	public String formatMessage(String rawMsg){

		Date time = new Date();
		rawMsg = time.toString() + " - " + userFullName + " \r\n\t" +rawMsg;
		return rawMsg;

	}

	public void addToDisplay(String content){
		chattingHistoryDisplay.setText( chattingHistoryDisplay.getText() +"\r\n" + content);
	}

	public void sendMessage(String message){
		userService.sendMessageToBuffer(userId, selectedContactId, message, new AsyncCallback<Void>(){

			@Override
			public void onFailure(Throwable caught) {
				//		Window.alert("sendMessageToBuffer Failure");				
			}

			@Override
			public void onSuccess(Void result) {

			}			
		});
	}

	public void requestMessage(){
		userService.requestMessage(userId, selectedContactId, new AsyncCallback<String>(){
			@Override
			public void onFailure(Throwable caught) {
				Window.alert("sendMessageToBuffer Failure");				
			}

			@Override
			public void onSuccess(String result) {
				//		Window.alert("TRACK - result is _"+result+"_");
				if(result==null || result.equals("") || result.equals("\n") || result.equals("\r") || result.equals("\r\n")){	
					return;	// Discard
				}	
				addToLocalChattingHistory(result);
				addToDisplay(result);
			}			
		});
	}

	// This function will be used with either sending a message or receiving a message
	public void addToLocalChattingHistory(String message){
		String temp = message;
		if(chattingHistoryStoreLocal.get(selectedContactId)!=null)		// We don't overwrite
			temp = chattingHistoryStoreLocal.get(selectedContactId) + "\r\n" + temp;		
		chattingHistoryStoreLocal.put(selectedContactId, temp);	// UserId is the key, chatting History is the value

	}

	/*--------------------- Chatting Environment -----------------------------*/
	// This function will be used upon any updates of the contact list

	public void updateChattingEnvironment(){
		for(Quad<String, String, String, String> p: contactInfoBundleList){
			String temp = "";
			if(chattingHistoryStoreLocal.get(p.getA())!=null)		// We don't overwrite
				temp = temp + chattingHistoryStoreLocal.get(p.getA()) + "\r\n";		
			chattingHistoryStoreLocal.put(p.getA(), temp);	// UserId is the key, chatting History is the value
			if(p.getA().equals(selectedContactId))
				selectedContactLogin = p.getB();
		}		
	}



	/*--------------------- Asynchronouos Mechanisms -----------------------------*/

	public void startMessageQueryProcess(final int interval){
		userService.timmer(interval, new AsyncCallback<Void>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Asynchronouos Request Message Mechanism - DOWN!");
			}

			@Override
			public void onSuccess(Void result) {
				requestMessage();
				startMessageQueryProcess(interval);
			}

		});
	}

	public void startContactUpdateProcess(final int interval){
		userService.timmer(interval, new AsyncCallback<Void>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Asynchronouos Request Message Mechanism - DOWN!");
			}

			@Override
			public void onSuccess(Void result) {
				updateAndRefreshContacts();
				startMessageQueryProcess(interval);
			}

		});
	}


}
